﻿using FTI.Core;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FTI.Milliman.Source
{
    [Export(typeof(ISource))]
    public class Source
        : ISource
    {
        internal class Columns
        {
            public const string Date = "Date";
            public const string Security = "Security";
            public const string Source = "Source";
            public const string Amount = "Amount";
            public const string Units = "Units";
            public const string Type = "Type";
            public const string Price = "Price";
            public const string Unknown = "Unknown";
        }

        internal enum TransactionType
            : int
        {
            Unknown = 0,
            //[DisplayName("Contribution Recieved")] need to think of something to make this possible
            [Description("Contribution")]
            Contribution,
            //[DisplayName("Earn Gain/Loss")]
            [Description("Earn Gain/Loss")]
            EarnGainOrLoss,
            //[DisplayName("Earnings Dividend")]
            [Description("Dividends")]
            Dividends,
            //[DisplayName("Transfer-In")]
            [Description("Transfer In")]
            TransferIn,
            //[DisplayName("Transfer-Out")]
            [Description("Transfer Out")]
            TransferOut
        }

        [Import("SystemEventLog", typeof(IEventLogging))]
        public IEventLogging Log { get; set; }

        public string Name
        {
            get { return Resources.SourceName; }
        }

        public string Description
        {
            get { return String.Format(Resources.SourceDescription, Name); }
        }

        public string Extension
        {
            get { return Resources.SourceExtension; }
        }

        public Encoding Encoding
        {
            get { return Encoding.UTF8; }
        }

        public string Location { get; set; }

        /// <summary>
        /// This value will always be false since Milliman Benefits does not support remote retrieval
        /// </summary>
        public bool IsRemoteLocation
        {
            get { return false; }
        }

        public bool EnableConcurrency
        {
            get;
            set;
        }

        public bool GetDataFromSource(string path, ref DataSet data)
        {
            byte[] oData = new byte[] { };  // initialized as an empty byte array

            bool success = false;

            if(data == null)
            {
                throw new ArgumentNullException("pData", "DataSet Reference should not be passed as null.");
            }

            DataTable oTable = new DataTable(Name);

            #region table schema

            oTable.Columns.Add(new DataColumn(Columns.Date, typeof(DateTime))
            {
                AllowDBNull = false,
                DateTimeMode = DataSetDateTime.Local
            });
            oTable.Columns.Add(new DataColumn(Columns.Security, typeof(String))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Source, typeof(String))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Amount, typeof(Decimal))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Units, typeof(Decimal))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Type, typeof(String))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Price, typeof(Decimal))
            {
                AllowDBNull = false
            });
            oTable.Columns.Add(new DataColumn(Columns.Unknown, typeof(String))
            {
                AllowDBNull = true
            });

            #endregion

            data.Tables.Add(oTable);

             using(FileStream oStream = new FileStream(path, FileMode.Open, FileAccess.Read))
             using (CSVFileReader oReader = new CSVFileReader(oStream, Encoding))
             {
                 try
                 {
                     oReader.EnableConcurrency = EnableConcurrency;

                     if (!oReader.Read(ref oTable))
                     {   // if this logical block is accessed there are errors encountered during the import.
                         Log.Write(String.Format(Resources.FileImportErrors, path), EventLogEntryType.Error, SystemCategory.Source, Encoding.UTF8.GetBytes(oReader.Errors));
                     }

                     success = oReader.Errors.Length == 0;
                 }
                 catch (Exception pEx)
                 {
                     Log.Write(String.Format("{0}: {1}", Name, pEx.Message), EventLogEntryType.Error, SystemCategory.Source, Encoding.UTF8.GetBytes(pEx.ToString()));

                     success = false;
                 }
             }

             return success;
        }
    }
}
